[イベントレポート] Wantedly 技術見学会 〜iOS編〜 に参加してきました! #WT技術見学会

[イベントレポート] Wantedly 技術見学会 〜iOS編〜 に参加してきました! #WT技術見学会

Clock Icon2017.05.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

おばんです、一人暮らしを開始してからAmazonのサービスを利用することが増え、今回のWWDC用品を購入する際にお急ぎ便が無料になるということだったので勢いで Amazon Prime に加入した田中です。 Prime Video に期待。?

今回は Wantedly さんで開催された 「Wantedly 技術見学会 〜iOS編〜」 のレポートをお届けします!

イベント概要

WantedlyのiOS開発に焦点を当て、iOSアプリを長期的に開発・運用する上で学んだ知見を共有します。

今回は

・開発開始から4年の会社訪問アプリ「Wantedly Visit」 ・10枚の名刺を瞬時にデータ化する名刺管理アプリ「Wantedly People」 の2つのアプリの開発メンバーが発表します。

Connpassより引用

発表内容

「Wantedly People ViewModel with Rx」 杉上 洋平 さん

Wantedly People の RxSwift × MVVM のお話。

Wantedly Peopleは名刺管理をするアプリ。同時に10枚の名刺をカメラで認識して登録することが可能であることが目玉の一つ。

  • ViewModelのイニシャライズについて
    • インプットとなる状態変化はプロパティにしない
    • イニシャライザで代入して、UIViewControllerからのバインディングの漏れを防止している
    • それによって初期化時に必要な情報を明文化している
  • ViewModelの外部要因を疎結合に(依存性の注入)
    • プロトコルに依存する形で実装している
    • Dependenciesというprotocolを作成している
    • DependenciesはAPIKitというライブラリを参考にしている
    • 依存性の注入によってテスト時に実装を差し替えるなどが可能になる
    • Androidにはdaggerなどがあるが、Swiftの場合は言語そのものの機能でも十分実装可能
  • ViewModelのインスタンス化(疎結合にする場合)
    • UIViewControllerのイニシャライズでViewModelを代入している

ViewControllerの初期化時にViewModelを代入しているということは、UIStoryboardから初期化してない? #WT技術見学会

— ダンボー田中 (@ktanaka117) 2017年5月31日

  • ViewModelの入力精査
    • (コード解説)
    • 入力精査の状態管理はenumで定義している
  • ViewModelの通信処理
    • 通信中とエラーハンドリング
      • (コード解説)
  • 設計について
    • ViewModelから限定的にWireframeを介してRoutingなどを行なっている

Viperアーキテクチャ(Clean Architecture for iOS)のWireframeを使っている #WT技術見学会

— ダンボー田中 (@ktanaka117) 2017年5月31日

Wireframeを扱うのってもともと、ViewModelかPresenterという認識だった。MVVM崩しと言うのは、部分的にViperの要素を取り入れていると言うことかな? #WT技術見学会

— ダンボー田中 (@ktanaka117) 2017年5月31日

  • ActivityIndicator
    • MBProgressHUDをRx拡張して使っている
  • RetryWhenConfirmRetryAlert
    • UIAlertでリトライする処理をオペレータ化した
  • Realm中心設計

プロフィール画面を表示していて、そこの一個先の画面遷移で書き換えたプロフィールのデータをどうやって一個前の画面にデータを反映させるか問題。
RxRealmを使っている。https://t.co/3Pqn6VPcsR#WT技術見学会

— ダンボー田中 (@ktanaka117) 2017年5月31日

「Wantedly Peopleのスキャン画面の裏側」 後藤 慎一 さん

Wantedly Peopleの名刺をスキャンする画面の裏話。技術要素として珍しいものなのでぜひ話をしたいというのと、不安定なスキャン結果をどう処理するかなど。

  • スキャン画面の処理の流れ
    • 名刺が検出されるとユーザーに検出されたことがわかる
    • ユーザーの任意のタイミングで名刺の検出の最終結果を取得する
      • OCRやClassificationはサーバーサイドで行う
      • この後に、Wantedlyユーザーとの紐付けもサーバーサイドで行なっている
    • 最後に結果を画面にレスポンスを返す
  • 要素技術
    • AVFoundationとOpenCVを利用している
      • 名刺検出のOpenCV以外の選択肢としてMetalなどもあった
      • しかし、iOSのバージョン対応やAndroidと統一するためにOpenCVを利用するという決定をした
    • 言語選択
      • OpenCVを扱うため、画像検出部分に関してはObjective-C++に寄せた
  • 不安定な検出結果の対処
    • 名刺領域の検出
      • 名刺スキャン時にシャッター音を鳴らしたくないのでAVCaptureVideoDataOutputを利用した
    • カメラがブレる問題
      • シーケンスとして扱う
      • 連続するフレームのシーケンスを、フレームの鮮明度の比較によって確からしいフレームの画像を利用することでブレの問題を解消している
      • フレームの鮮明度はラプラシアンフィルタをかけた結果の分散をみている
    • 名刺のTracking
      • ResultsQueueを利用している
    • これらの処理によって不安定な検出結果が劇的に改善した
  • デバッグ版の開発
    • リアルタイムな画像処理アプリの開発で困ること
      • 演算状況、リソース状況を表示していた
      • 演算の過程を分割した画面上に表示して、どこの演算処理で結果が悪くなっているかのデバッグを行なっていた

「Wantedly Peopleの連絡先一覧について」 多和田 侑 さん

Wantedly Peopleには連絡先一覧画面があり、電話をかけたりメールを送信したりできる。その画面に関する発表です。

  • 状態について
    • ログイン必須の場合
      • インストール直後にWantedlyの連絡先一覧を読み込む
      • 連絡先一覧の同期
    • 後から新規登録 or ログイン
      • あとでマージする
  • 単純なデータ同期(後からログイン)
    • last_fetched_atのデータを元に、時間を元にデータをマージする
    • last_fetched_atより古い情報の場合はマージできないという問題
  • データ同期(差分取得API / contacts / diff)
    • ids
      • アプリ側ですでにキャッシュしているデータのID
    • last_fetched_at
      • 前回のデータ同期日時
    • revision
      • 前回のデータ同期時のリビジョン
    • これらをサーバーサイドに送って、比較してマージを行なっている
  • アプリが凄く重たい問題
    • 連絡先3000件でデバッグ
      • 計測してみたら起動してからカメラがactivateするまで7秒ぐらいかかった
    • 原因
      • Realmオブジェクトからstructへの変換
        • RLMObject -> Struct
        • 連絡先10000件だと80秒(iPhone7)かかった
      • 並べ替えのインデックスの生成
        • 重複するデータの削除など
    • 解決策
      • Realmオブジェクトからstructへの変換
        • 一般化されたデータモデルと表示に必要な内容が異なるので、プロパティを減らしたデータモデルを作って変換コストを下げた
      • 並べ替えのインデックスの生成
        • ソートをRealmの機能に頼った

プロパティを減らすだけで80秒が2.5秒になったのかw #WT技術見学会

— Tatsuya Tanaka (@tanakasan2525) 2017年5月31日

「Wantedly Visitの検索・フィルター機能」 藤原 慶貴 さん

[後ほどスライドを挿入します]

Wantedly Visitのエンドユーザー向けの改善を行うチームの方からのお話。

  • WantedlyではWhyとHowを大事にしている
  • Why
    • 課題を見つける
      • どういう風にアプリが使われているかの分析
      • 滞在時間で区切る、画面別に行動を見る、など
    • 検索の課題
      • 社名での検索が多い
      • 業種などを変えるなどの試行錯誤が多い
    • 仮説を立てる
      • なぜアプリは社名の検索が多いのか?
      • 知りたい会社名を外部で知っていて検索する?
  • How
    • 仮説を検証する
      • Webで最近表示したものを試しに画面上部に表示
      • ボーナスが出た後の月は検索が増える
      • ABテスト
      • 社名での検索割合はほとんどかわらない
      • 応募ユーザ数は約10%増
    • 次のステップ
      • より簡単に、できるだけ少ないタイプ数で知っている社名にたどり着きたい
      • どういう特徴をサジェストするべきかなどの試行錯誤
  • Wantedlyでは仮説と検証を繰り返すというワークフローが特徴になっている!
  • VisitのiOSアプリについて
    • 古い部分はObjective-C、新しい部分はSwiftで書いていくスタイル
    • Cellの種類が増えてくる
      • ABテストをしているとCellの種類が増える
      • ContentInset/Offsetが混み合う
      • Cellに表示したいコンテンツにreuseIdentifierを持たせるなどの工夫
    • ViewModelを分割するべきか
      • 一箇所でbindするとfat ViewControllerみたいになってしまう?
      • ViewControllerを分割して子のViewControllerを作るなどしたが、逆にわかりづらくなった
  • Wantedlyの文化的なところ
    • UIの軽微なバグが蓄積していく
      • 負債返済日を作って一気に修正している
    • Zeplinが便利
      • デザイナーに頼まなくても、Sketchから直接pngを抽出できたりして便利
    • 自分たちの仕事をラクにするツールを開発するハッカソンを実施している

「限られたリソースで進める段階的なSwift移行」 永島 次朗 さん

Swiftの移行にともなう困難があったけど、いかに工夫して乗り越えたかという話。

  • Swiftの行こうと並行して解決すべき課題
    • 限られたリソース
      • 新規事業への注力で一時期は一人で開発
      • グロースチームのエンジニアの業務は単純な開発だけではないのでやることが多い
    • ネットワーク層の再設計の必要性
      • RestKitをアプリのリリース時から利用していた
      • しかしRestKitには課題があった
        • Objective-Cなのでメンテナンスの頻度が低くなっていった
        • AFNetworking 1.x系に依存していた(一部クラッシュ要因になっていた)
    • リスト表示の再設計の必要性
      • コンテンツの多様化と複雑化
  • リソースが限られている中でのSwift以降は上記の課題によって難しいものだった
  • 段階的なSwift移行
    • フェーズ1. Objective-CのプロジェクトへのSwiftの部分導入
    • フェーズ2. 代替の実装の適用(サブ画面)
    • フェーズ3. 代替の実装の適用(メイン画面)

おわりに

やっぱりWantedlyはやってることがリッチで、エンジニア冥利につきることをやっているなあという感想を持つ、そんな会でした!

全編を通してRxSwift, MVVMが利用されていることが強調されていて、発表とそれに対するTwitterのタイムライン上の反応を眺めていてもその普及度合いがよくわかる印象を受けました。


Wantedlyさんはクラスメソッド入社前の学生時代に2週間ほどインターンをさせていただいていたので、久々にオフィスにお邪魔させていただいてなつかしく思いました。今度サマーインターンを開催されるそうなので、そちらもご興味あれば!

圧倒的成長できます。?

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.